package com.person.yhzs.config;

import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.person.yhzs.annotation.Authorized;
import com.person.yhzs.common.Constants;
import com.person.yhzs.exception.UnAuthorizedException;
import com.person.yhzs.user.entity.User;
import com.person.yhzs.util.JwtUtil;
import com.person.yhzs.util.RedisUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;


public class AuthorizationInterceptor implements HandlerInterceptor {
    static final Logger LOGGER = LoggerFactory.getLogger(AuthorizationInterceptor.class);
    static final String USER_ID = "userId";
    RedisUtil redisUtil;

    public AuthorizationInterceptor(RedisUtil redisUtil) {
        this.redisUtil = redisUtil;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        LOGGER.info("received request");
        if (!(handler instanceof HandlerMethod)) {
            //no annotation
            return true;
        }
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Class<?> beanType = handlerMethod.getBeanType();
        Method method = handlerMethod.getMethod();
        //如果没有 Authorized，不进行验证
        if (beanType.getAnnotation(Authorized.class) == null
                && method.getAnnotation(Authorized.class) == null) {
            //无需处理

        } else {
            //从Header中得到token
            String token = request.getHeader(JwtUtil.KEY_USER_TOKEN);
            Integer userId = null;
            if (StringUtils.isBlank(token)) {
                throw new UnAuthorizedException("未认证");
            } else {
                User user = checkUserAuth(token);
                userId = user.getId();
            }
            request.setAttribute(USER_ID, userId);
        }
        return true;
    }

    boolean hasAttribute(Parameter[] parameters, String name) {
        if (parameters != null && parameters.length > 0) {
            for (Parameter p : parameters) {
                if (p.getName().equals(name)) {
                    return true;
                }
            }
        }
        return false;
    }

    User checkUserAuth(String userToken) {
        if (StringUtils.isBlank(userToken)) {
            throw new UnAuthorizedException("请登录");
        }
        User user = null;
        try {
            user = JwtUtil.decodeUserToken(userToken);
        } catch (JWTDecodeException | SignatureVerificationException e) {
            throw new UnAuthorizedException("无效凭证，请登录");
        }
        if (user == null) {
            throw new UnAuthorizedException("无效凭证，请重新登录");
        }
        String key = String.format(RedisUtil.KEY_USER_ID, user.getId());
        String cacheToken = (String) redisUtil.get(key);
        if (StringUtils.isBlank(cacheToken)) {
            throw new UnAuthorizedException("登录已失效，请重新登录");
        }
        String simpleToken = userToken.substring(userToken.length() - RedisUtil.USER_TOKEN_CACHE_LEN);
        if (!simpleToken.equals(cacheToken)) {
            throw new UnAuthorizedException("此账户可能已在别处登录，请重新登录");
        }
        //refresh expiration of user session
        redisUtil.set(key, simpleToken, Constants.USER_SESSION_IDLE_DURATION);
        return user;
    }

}
